package com.chengshuang.log.config;

import com.chengshuang.log.annotation.LogRecord;
import com.chengshuang.log.constant.LogConstant;
import com.chengshuang.log.factory.FunctionFactory;
import com.chengshuang.log.fuction.LogRecordFunction;
import com.chengshuang.log.fuction.LogRecordSnapshotFunction;
import com.chengshuang.log.utils.LogParseUtils;
import java.lang.reflect.Method;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ConfigurationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

/**
 * Spring初始化
 *
 * @author shuang.cheng
 * @date 2022/10/13
 */
@Component
public class SrpingInitializing implements InitializingBean {

    private static final Logger log = LoggerFactory.getLogger(SrpingInitializing.class);

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public void afterPropertiesSet() {
        //动态模板初始化
        Reflections reflections = new Reflections(new ConfigurationBuilder()
            .forPackages("com.chengshuang")
            .addScanners(new MethodAnnotationsScanner()));
        Set<Method> methods = reflections.getMethodsAnnotatedWith(LogRecord.class);
        if (CollectionUtils.isNotEmpty(methods)) {
            log.info("扫描到如下日志记录方法：");
        }
        for (Method method : methods) {
            LogRecord annotation = method.getAnnotation(LogRecord.class);
            String methodName = method.toGenericString();
            log.info(methodName);
            buildDynamicTemplate(methodName, annotation);
        }
        //快照初始化
        Set<Class<? extends LogRecordSnapshotFunction>> snapshotClasses = reflections.getSubTypesOf(LogRecordSnapshotFunction.class);
        initMyLogRecordSnapshotFunctions(snapshotClasses);
        //自定义函数初始化
        Set<Class<? extends LogRecordFunction>> classes = reflections.getSubTypesOf(LogRecordFunction.class);
        initMyLogRecordFunctions(classes);
    }

    private void buildDynamicTemplate(String methodName, LogRecord annotation) {
        //relationId
        String relationId = annotation.relationId();
        LogParseUtils.initDynamicTemplate(methodName, LogConstant.RELATION_ID, relationId);
        //operatorId
        String operatorId = annotation.operatorId();
        LogParseUtils.initDynamicTemplate(methodName, LogConstant.OPERATOR_ID, operatorId);
        //description
        String description = annotation.description();
        LogParseUtils.initDynamicTemplate(methodName, LogConstant.DESCRIPTION, description);
        //snapshot
        String snapshot = annotation.snapshot();
        LogParseUtils.initDynamicTemplate(methodName, LogConstant.SNAPSHOT, snapshot);
    }

    private void initMyLogRecordSnapshotFunctions(Set<Class<? extends LogRecordSnapshotFunction>> classes) {
        if (CollectionUtils.isEmpty(classes)) {
            return;
        }

        log.info("扫描到如下快照方法：");
        for (Class<? extends LogRecordSnapshotFunction> clazz : classes) {
            LogRecordSnapshotFunction bean = applicationContext.getBean(clazz);
            String functionName = bean.functionName();
            log.info(functionName);
            LogParseUtils.validateFunctionName(functionName);
            FunctionFactory.putSnapshotFunction(functionName, bean);
        }
    }

    private void initMyLogRecordFunctions(Set<Class<? extends LogRecordFunction>> classes) {
        if (CollectionUtils.isEmpty(classes)) {
            return;
        }

        log.info("扫描到如下自定义函数：");
        for (Class<? extends LogRecordFunction> clazz : classes) {
            LogRecordFunction bean = applicationContext.getBean(clazz);
            String functionName = bean.functionName();
            log.info(functionName);
            LogParseUtils.validateFunctionName(functionName);
            boolean executeBefore = bean.executeBefore();
            if (executeBefore) {
                FunctionFactory.putBeforeFunction(functionName, bean);
            } else {
                FunctionFactory.putAfterFunction(functionName, bean);
            }
        }
    }
}
